home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / macros / texinfo / info / footnotes.c < prev    next >
C/C++ Source or Header  |  1994-01-28  |  7KB  |  265 lines

  1. /* footnotes.c -- Some functions for manipulating footnotes. */
  2.  
  3. /* This file is part of GNU Info, a program for reading online documentation
  4.    stored in Info format.
  5.  
  6.    Copyright (C) 1993 Free Software Foundation, Inc.
  7.  
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2, or (at your option)
  11.    any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22.    Written by Brian Fox (bfox@ai.mit.edu). */
  23.  
  24. #include "info.h"
  25.  
  26. /* Non-zero means attempt to show footnotes when displaying a new window. */
  27. int auto_footnotes_p = 1;
  28.  
  29. static char *footnote_nodename = "*Footnotes*";
  30.  
  31. #define FOOTNOTE_HEADER_FORMAT \
  32.    "*** Footnotes appearing in the node \"%s\" ***\n"
  33.  
  34. /* Find the window currently showing footnotes. */
  35. static WINDOW *
  36. find_footnotes_window ()
  37. {
  38.   WINDOW *win;
  39.  
  40.   /* Try to find an existing window first. */
  41.   for (win = windows; win; win = win->next)
  42.     if (internal_info_node_p (win->node) &&
  43.     (strcmp (win->node->nodename, footnote_nodename) == 0))
  44.       break;
  45.  
  46.   return (win);
  47. }
  48.  
  49. /* Manufacture a node containing the footnotes of this node, and
  50.    return the manufactured node.  If NODE has no footnotes, return a 
  51.    NULL pointer. */
  52. NODE *
  53. make_footnotes_node (node)
  54.      NODE *node;
  55. {
  56.   NODE *fn_node, *result = (NODE *)NULL;
  57.   long fn_start;
  58.  
  59.   /* Make the initial assumption that the footnotes appear as simple
  60.      text within this windows node. */
  61.   fn_node = node;
  62.  
  63.   /* See if this node contains the magic footnote label. */
  64.   fn_start =
  65.     info_search_in_node (FOOTNOTE_LABEL, node, 0, (WINDOW *)NULL, 1);
  66.  
  67.   /* If it doesn't, check to see if it has an associated footnotes node. */
  68.   if (fn_start == -1)
  69.     {
  70.       REFERENCE **refs;
  71.  
  72.       refs = info_xrefs_of_node (node);
  73.  
  74.       if (refs)
  75.     {
  76.       register int i;
  77.       char *refname;
  78.  
  79.       refname = (char *)xmalloc
  80.         (1 + strlen ("-Footnotes") + strlen (node->nodename));
  81.  
  82.       strcpy (refname, node->nodename);
  83.       strcat (refname, "-Footnotes");
  84.  
  85.       for (i = 0; refs[i]; i++)
  86.         if (strcmp (refs[i]->nodename, refname) == 0)
  87.           {
  88.         char *filename;
  89.  
  90.         filename = node->parent;
  91.         if (!filename)
  92.           filename = node->filename;
  93.  
  94.         fn_node = info_get_node (filename, refname);
  95.  
  96.         if (fn_node)
  97.           fn_start = 0;
  98.  
  99.         break;
  100.           }
  101.  
  102.       free (refname);
  103.       info_free_references (refs);
  104.     }
  105.     }
  106.  
  107.   /* If we never found the start of a footnotes area, quit now. */
  108.   if (fn_start == -1)
  109.     return ((NODE *)NULL);
  110.  
  111.   /* Make the new node. */
  112.   result = (NODE *)xmalloc (sizeof (NODE));
  113.   result->flags = 0;
  114.  
  115.   /* Get the size of the footnotes appearing within this node. */
  116.   {
  117.     char *header;
  118.     long text_start = fn_start;
  119.  
  120.     header = (char *)xmalloc
  121.       (1 + strlen (node->nodename) + strlen (FOOTNOTE_HEADER_FORMAT));
  122.     sprintf (header, FOOTNOTE_HEADER_FORMAT, node->nodename);
  123.  
  124.     /* Move the start of the displayed text to right after the first line.
  125.        This effectively skips either "---- footno...", or "File: foo...". */
  126.     while (text_start < fn_node->nodelen)
  127.       if (fn_node->contents[text_start++] == '\n')
  128.     break;
  129.   
  130.     result->nodelen = strlen (header) + fn_node->nodelen - text_start;
  131.  
  132.     /* Set the contents of this node. */
  133.     result->contents = (char *)xmalloc (1 + result->nodelen);
  134.     sprintf (result->contents, "%s", header);
  135.     memcpy (result->contents + strlen (header),
  136.         fn_node->contents + text_start, fn_node->nodelen - text_start);
  137.  
  138.     name_internal_node (result, footnote_nodename);
  139.     free (header);
  140.   }
  141.  
  142. #if defined (NOTDEF)
  143.   /* If the footnotes were gleaned from the node that we were called with,
  144.      shorten the calling node's display length. */
  145.   if (fn_node == node)
  146.     narrow_node (node, 0, fn_start);
  147. #endif /* NOTDEF */
  148.  
  149.   return (result);
  150. }
  151.  
  152. /* Create or delete the footnotes window depending on whether footnotes
  153.    exist in WINDOW's node or not.  Returns FN_FOUND if footnotes were found
  154.    and displayed.  Returns FN_UNFOUND if there were no footnotes found
  155.    in WINDOW's node.  Returns FN_UNABLE if there were footnotes, but the
  156.    window to show them couldn't be made. */
  157. int
  158. info_get_or_remove_footnotes (window)
  159.      WINDOW *window;
  160. {
  161.   WINDOW *fn_win;
  162.   NODE *new_footnotes;
  163.  
  164.   fn_win = find_footnotes_window ();
  165.  
  166.   /* If we are in the footnotes window, change nothing. */
  167.   if (fn_win == window)
  168.     return (FN_FOUND);
  169.  
  170.   /* Try to find footnotes for this window's node. */
  171.   new_footnotes = make_footnotes_node (window->node);
  172.  
  173.   /* If there was a window showing footnotes, and there are no footnotes
  174.      for the current window, delete the old footnote window. */
  175.   if (fn_win && !new_footnotes)
  176.     {
  177.       if (windows->next)
  178.     info_delete_window_internal (fn_win);
  179.     }
  180.  
  181.   /* If there are footnotes for this window's node, but no window around
  182.      showing footnotes, try to make a new window. */
  183.   if (new_footnotes && !fn_win)
  184.     {
  185.       WINDOW *old_active;
  186.       WINDOW *last, *win;
  187.  
  188.       /* Always make this window be the last one appearing in the list.  Find
  189.      the last window in the chain. */
  190.       for (win = windows, last = windows; win; last = win, win = win->next);
  191.  
  192.       /* Try to split this window, and make the split window the one to
  193.      contain the footnotes. */
  194.       old_active = active_window;
  195.       active_window = last;
  196.       fn_win = window_make_window (new_footnotes);
  197.       active_window = old_active;
  198.  
  199.       if (!fn_win)
  200.     {
  201.       free (new_footnotes->contents);
  202.       free (new_footnotes);
  203.  
  204.       /* If we are hacking automatic footnotes, and there are footnotes
  205.          but we couldn't display them, print a message to that effect. */
  206.       if (auto_footnotes_p)
  207.         inform_in_echo_area ("Footnotes could not be displayed");
  208.       return (FN_UNABLE);
  209.     }
  210.     }
  211.  
  212.   /* If there are footnotes, and there is a window to display them,
  213.      make that window be the number of lines appearing in the footnotes. */
  214.   if (new_footnotes && fn_win)
  215.     {
  216.       window_set_node_of_window (fn_win, new_footnotes);
  217.  
  218.       window_change_window_height
  219.     (fn_win, fn_win->line_count - fn_win->height);
  220.  
  221.       remember_window_and_node (fn_win, new_footnotes);
  222.       add_gcable_pointer (new_footnotes->contents);
  223.     }
  224.  
  225.   if (!new_footnotes)
  226.     return (FN_UNFOUND);
  227.   else
  228.     return (FN_FOUND);
  229. }
  230.  
  231. /* Show the footnotes associated with this node in another window. */
  232. DECLARE_INFO_COMMAND (info_show_footnotes,
  233.    "Show the footnotes associated with this node in another window")
  234. {
  235.   int result;
  236.  
  237.   /* A negative argument means just make the window go away. */
  238.   if (count < 0)
  239.     {
  240.       WINDOW *fn_win = find_footnotes_window ();
  241.  
  242.       /* If there is an old footnotes window, and it isn't the only window
  243.      on the screen, delete it. */
  244.       if (fn_win && windows->next)
  245.     info_delete_window_internal (fn_win);
  246.     }
  247.   else
  248.     {
  249.       int result;
  250.  
  251.       result = info_get_or_remove_footnotes (window);
  252.  
  253.       switch (result)
  254.     {
  255.     case FN_UNFOUND:
  256.       info_error (NO_FOOT_NODE);
  257.       break;
  258.  
  259.     case FN_UNABLE:
  260.       info_error (WIN_TOO_SMALL);
  261.       break;
  262.     }
  263.     }
  264. }
  265.